/**
 * Copyright (c) 2010-2011 Pierre Labatut
 *
 * This file is part of Space-Chronicles project.
 *
 * Space-Chronicles is free software: you can redistribute it and/or modify it
 * under the terms of its license which may be found in the accompanying
 * LICENSE file or <http://code.google.com/p/space-chronicles/>.
 */
package space.game;

import space.video.VideoInitializationTask;
import space.audio.AudioInitializationTask;
import space.game.config.CfgResult;
import space.game.config.CfgCancelApplication;
import space.game.splash.CfgSplash;
import com.jogamp.opengl.util.Animator;
import java.awt.DisplayMode;
import java.awt.Frame;
import java.awt.GraphicsDevice;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.util.logging.Logger;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.awt.GLCanvas;
import javax.sound.sampled.Mixer;
import javax.sound.sampled.Mixer.Info;
import net.java.games.input.Controller;
import space.app.common.ErrorReportEventListener;
import space.input.CtlController;
import space.debug.DbgDialog;
import space.debug.GlobalParameters;
import space.debug.tune.Tunner;
import space.game.config.CfgSettings;
import space.input.InputInitializationTask;
import space.input.Record;
import space.input.RecordControler;

/**
 *
 * @author Pierre
 */
public class FwEnvironment {

    static private final Logger logger = Logger.getLogger(FwEnvironment.class.getName());
    private final GraphicsDevice gfxDevice;
    private final DisplayMode gfxMode;
    private final boolean gfxFullScreen;
    private final Mixer.Info sfxMixer;
    private final CtlController ctlDevice;
    private final DbgDialog ctlDbgDialog;
    private final File recordFile;
    private final Record record = new Record();

    public FwEnvironment(GraphicsDevice gfxDevice, DisplayMode gfxMode, boolean gfxFullScreen, Info sfxMixer, Controller ctrlDevice, File recordFile) {
        if (gfxDevice == null) {
            throw new IllegalArgumentException();
        }
        this.gfxDevice = gfxDevice;
        if (gfxMode == null) {
            throw new IllegalArgumentException();
        }
        this.gfxMode = gfxMode;
        this.gfxFullScreen = gfxFullScreen;
        if (sfxMixer == null) {
            throw new IllegalArgumentException();
        }
        this.sfxMixer = sfxMixer;
        if (ctrlDevice == null) {
            throw new IllegalArgumentException();
        }
        this.recordFile = recordFile;
        if (record == null) {
            this.ctlDevice = new CtlController(ctrlDevice);
        } else {
            this.ctlDevice = new CtlController(new RecordControler(ctrlDevice, record));
        }
        ctlDbgDialog = new DbgDialog(ctlDevice);
    }

    /**
     *
     */
    public static FwEnvironment initialize() throws CfgCancelApplication {
        /**
         * Display a progress bar and initialize every component of the framework
         */
        {
            final CfgSplash splash = new CfgSplash();
            splash.submit(new ChkEnvInitializationTask());
            splash.submit(new VideoInitializationTask());
            splash.submit(new InputInitializationTask());
            splash.submit(new AudioInitializationTask());
            splash.runAll();
        }

        final CfgResult configuration = CfgSettings.run();
        return new FwEnvironment(
                configuration.getGfxDevice(),
                configuration.getGfxMode(),
                configuration.isGfxFullScreen(),
                configuration.getSfxMixer(),
                configuration.getCtrlDevice(),
                configuration.getRecordFile());
    }

    void run() {
        final FwEventListener eventListener = new FwEventListener(this);
        /**
         * Création d'une fenêtre
         * Nous utilisons la classe Frame de AWT
         * plutôt que la classe JFrame de Swing
         * pour une question de performance
         */
        final Frame frame = new Frame(eventListener.toString());

        /**
         * Création du Canvas OpenGL
         * pour pouvoir dessiner dessus
         */
        final GLCanvas canvas = new GLCanvas();
        eventListener.listenToCanvas(canvas);
        eventListener.listenToFrame(frame);
        
        //canvas.setAutoSwapBufferMode(false);

        /**
         * Nous attachons maintenant notre
         * surface dessinable à notre fenêtre
         */
        frame.add(canvas);
        frame.addWindowListener(new WindowAdapter() {

            @Override
            public void windowClosing(WindowEvent e) {
                frame.setVisible(false);
                shutdown();
            }
        });

        /**
         * Nous donnons une taille à la fenêtre
         * et nous l'affichons
         */
        frame.setSize(gfxMode.getWidth(), gfxMode.getHeight());
        //frame.setSize(512+512-504,512+512-478);
        frame.setLocationRelativeTo(null);
        
        canvas.addKeyListener(new KeyAdapter() {

            @Override
            public void keyPressed(KeyEvent e) {
                if ((e.isControlDown() == true && e.getKeyCode() == KeyEvent.VK_W)
                        || (e.getKeyCode() == KeyEvent.VK_ESCAPE)) {
                    frame.dispatchEvent(new WindowEvent(frame, WindowEvent.WINDOW_CLOSING));
                }
            }
        });

        if (gfxFullScreen) {
            frame.setUndecorated(true);
            gfxDevice.setFullScreenWindow(frame);
            gfxDevice.setDisplayMode(gfxMode);
        }

        /**
         * Show GL Frame
         */
        frame.setVisible(true);
        /**
         * Show allways on top controller frame only if necessary
         */
        if (gfxFullScreen == false) {
            if (GlobalParameters.showFPSDebugger) {
                ctlDbgDialog.setVisible(true);
            }
            new Tunner(GlobalParameters.class).setVisible(true);
        }
        /**
         * Give the focus to the canvas so that keybord events can be cautch
         * http://tech.stolsvik.com/2009/03/awt-swing-event-pumping-and-targeting.html
         */
        canvas.requestFocusInWindow();
        final Animator anim = new Animator(canvas);
        anim.start();



    }

    public CtlController getCtlDevice() {
        return ctlDevice;
    }

    public void update(long frmTimeStamp, long rndrElapsed, long lgcElapsed) {
        ctlDbgDialog.update(frmTimeStamp, rndrElapsed, lgcElapsed);
    }

    void shutdown() {
        System.out.println("Closing");
        try {
            if (gfxFullScreen) {
                gfxDevice.setFullScreenWindow(null);
            }

            if (recordFile != null) {
                record.save(recordFile);
            }
        } finally {
            System.exit(0);
        }
    }
}
